using System;
using System.IO;
using System.Windows.Forms;
using System.Collections;

using EA;

namespace OpenEdge.DatabaseEngineering.Import
{
	/// <summary>
	/// Summary description for Importer.
	/// </summary>
	public class Importer : IDisposable
	{

		public delegate void LogRequest(string messageString);
		public delegate void ProgressRequest(int numChars);
		public delegate void EndRequest();

		public event LogRequest			LogWriteLine;
		public event ProgressRequest	progressNumChars;
		public event ProgressRequest    progressLength;
		public event EndRequest			importEnd;

		private EA.Repository	eaRepository;
		private FileStream		fileStream;
		private StreamReader	streamReader;

		public Importer(EA.Repository eaRepository)
		{
			
			this.eaRepository = eaRepository;
		}

		public void import(String filePath, String packageName, bool createRelationships) 
		{

			string objectType = eaRepository.GetTreeSelectedItemType().ToString();

			if (objectType != "otPackage")
				System.Windows.Forms.MessageBox.Show("Package not selected");
			else
			{
				this.fileStream		= new FileStream(filePath,
													 System.IO.FileMode.Open,
													 System.IO.FileAccess.Read,
													 System.IO.FileShare.Read);					
				this.streamReader	= new StreamReader(fileStream);

				this.LogWriteLine("FileStream length = " + this.fileStream.Length);
				this.progressLength( (int) this.fileStream.Length);

				Object		currentObject      = null;
				EA.Package	currentPackage     = null;				

				eaRepository.GetTreeSelectedItem(out currentObject);
				currentPackage = (EA.Package) currentObject;

				if (packageName.Length > 0)
				{
					EA.Package newPackage = (EA.Package) currentPackage.Packages.AddNew(packageName, "database");
                    newPackage.IsNamespace = true;
					newPackage.Update();
					currentPackage.Elements.Refresh();


					EA.Element newElement = newPackage.Element;
					newElement.Stereotype = "database";
					newElement.Gentype    = "OpenEdge DB";
					newElement.Update();
					newElement.Refresh();

					currentPackage = newPackage;
				}

				try 
				{
					this.eaRepository.BatchAppend		= true;
					this.eaRepository.EnableUIUpdates	= false;
					this.eaRepository.FlagUpdate		= true;

					String line;
					char[] separator = {' '};

					while ((line = this.streamReader.ReadLine()) != null) 
					{
						String[] lineTokens = line.Split(separator);
						
						String tableName	= null;
						String fieldName	= null;
						String indexName	= null;
						String sequenceName = null;
						String dataType		= null;
						String oldIndexName = null;

						char[] trimchars = {'\"'};

						switch (lineTokens[0])
						{
							case "ADD":
								switch(lineTokens[1])
								{
									case "TABLE":
										tableName = lineTokens[2].Trim(trimchars);
										addTable(currentPackage, tableName);	
										break;
									case "FIELD":
										fieldName = lineTokens[2].Trim(trimchars);
										tableName = lineTokens[4].Trim(trimchars);
										dataType  = lineTokens[6].Trim(trimchars);
										addField(currentPackage, fieldName, tableName, dataType);
										break;
									case "INDEX":
										indexName = lineTokens[2].Trim(trimchars);
										tableName = lineTokens[4].Trim(trimchars);
										addIndex(currentPackage, indexName, tableName);
										break;
									case "SEQUENCE":
										sequenceName = lineTokens[2].Trim(trimchars);
										addSequence(currentPackage, sequenceName);
										break;
									default:
										break;
								}
								break;
							case "UPDATE":
								switch(lineTokens[1])
								{
									case "TABLE":
										tableName = lineTokens[2].Trim(trimchars);
										/* updateTable(currentPackage, tableName);	*/
										break;
									case "FIELD":
										fieldName = lineTokens[2].Trim(trimchars);
										tableName = lineTokens[4].Trim(trimchars);
										/* updateField(currentPackage, fieldName, tableName); */
										break;
									case "PRIMARY":
										switch(lineTokens[2])
										{
											case "INDEX":
												indexName = lineTokens[3].Trim(trimchars);
												tableName = lineTokens[5].Trim(trimchars);
												/* updatePrimaryIndex(currentPackage, indexName, tableName); */
												break;
											default:
												break;
										}
										break;
									case "SEQUENCE":
										sequenceName = lineTokens[2].Trim(trimchars);
										/* updateSequence(currentPackage, sequenceName); */
										break;
									default:
										break;
								}
								break;
							case "RENAME":
								switch(lineTokens[1])
								{
									case "INDEX":
										oldIndexName = lineTokens[2].Trim(trimchars);
										indexName    = lineTokens[4].Trim(trimchars);
										tableName    = lineTokens[6].Trim(trimchars);
										/* renameIndex(currentPackage, oldIndexName, indexName, tableName); */
										break;
									default:
										break;
								}
								break;
							case "DROP":
								switch(lineTokens[1])
								{
									case "TABLE":
										tableName = lineTokens[2].Trim(trimchars);
										/* dropTable(currentPackage, tableName);	*/
										break;
									case "FIELD":
										fieldName = lineTokens[2].Trim(trimchars);
										tableName = lineTokens[4].Trim(trimchars);
										/* dropField(currentPackage, fieldName, tableName); */
										break;
									case "INDEX":
										indexName = lineTokens[3].Trim(trimchars);
										tableName = lineTokens[5].Trim(trimchars);
										/* dropIndex(currentPackage, indexName, tableName); */
										break;
									case "SEQUENCE":
										sequenceName = lineTokens[2].Trim(trimchars);
										/* dropSequence(currentPackage, sequenceName); */
										break;
									default:
										break;
								}
								break;
							default:
								break;
						}
						
						this.progressNumChars(line.Length);
						GC.Collect();  
						GC.WaitForPendingFinalizers();   

					}

					if (createRelationships)
						createSchemaRelationships(currentPackage);

					createSchemaDiagram(currentPackage);

					/*
					foreach (EA.Element thisElement in currentPackage.Elements)
					{
						int pos = 0;
						this.LogWriteLine(thisElement.Name + " -- " + thisElement.TreePos.ToString());
						foreach(EA.Attribute thisAttribute in thisElement.Attributes)
						{							
							thisAttribute.Pos = pos;							
							thisAttribute.Update();
							
							this.LogWriteLine(thisAttribute.Name + " -- " + thisAttribute.Pos.ToString() + " -- " + pos.ToString());
							pos++;
						}
						thisElement.Attributes.Refresh();

						pos = 0;
						foreach(EA.Method thisMethod in thisElement.Methods)
						{							
							thisMethod.Pos = pos;
							thisMethod.Update();
							this.LogWriteLine(thisMethod.Name + " -- " + thisMethod.Pos.ToString() + " -- " + pos.ToString());
							pos++;
						}
						thisElement.Methods.Refresh();
						thisElement.Update();
					}
					currentPackage.Elements.Refresh();
					*/

					this.eaRepository.BatchAppend		= false;
					this.eaRepository.EnableUIUpdates	= true;				
					this.eaRepository.FlagUpdate		= false;				

					this.eaRepository.RefreshModelView(currentPackage.PackageID);						
					this.importEnd();

				}
				catch (Exception e) 
				{
					this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
				}
			}
		}

		private void addTable(EA.Package currentPackage, String tableName)
		{
			EA.Element     currentElement     = null;
			EA.TaggedValue currentTaggedValue = null;
				
			try
			{
				currentElement = (EA.Element) currentPackage.Elements.GetByName(tableName);
			}
			catch(Exception e)
			{                
                this.LogWriteLine(e.Message + ". Creating table - " + tableName + ".");    
			}

			if (currentElement == null) 
			{

				int treePos = currentPackage.Elements.Count;
				currentElement = (EA.Element) currentPackage.Elements.AddNew(tableName, "Class");
				currentElement.Stereotype = "table";
				currentElement.Gentype    = "OpenEdge DB";
				// currentElement.TreePos = treePos;
				currentElement.Update();
				
				char[] separator	= {' '};
				char[] trimchars	= {'\"'};
				String description	= "";
				String area         = "";
				String line			= null;
				short  idx          = 0;

				while ((line = this.streamReader.ReadLine()) != null)
				{
					if (line.Length == 0)
						break;

					String[] lineTokens = line.Split(separator);
				
					switch(lineTokens[2])
					{
						case "AREA":
							idx = 3;
							do 
							{
								for (; idx < lineTokens.Length; idx++)
								{
									area += lineTokens[idx];
									if (idx < (lineTokens.Length - 1))
										area += " ";
								}

								if (area.EndsWith("\""))
									break;

							} while (true);
							area = area.Trim(trimchars);
							currentElement.Tablespace = area;
							break;
						case "DESCRIPTION":
							idx = 3;
							do 
							{
								for (; idx < lineTokens.Length; idx++)
								{
									description += lineTokens[idx];
									if (idx < (lineTokens.Length - 1))
										description += " ";
								}

								if (description.EndsWith("\""))
									break;

								if ((line = this.streamReader.ReadLine()) != null)
								{
									lineTokens = line.Split(separator);
									idx = 0;
									this.progressNumChars(line.Length);
								}
								else
									break;
							} while (true);
							description = description.Trim(trimchars);
							currentElement.Notes = description;
							break;
						case "DUMP-NAME":
							currentTaggedValue = (EA.TaggedValue) currentElement.TaggedValues.GetByName(lineTokens[2]);
							if (currentTaggedValue == null) 
								currentTaggedValue = (EA.TaggedValue) currentElement.TaggedValues.AddNew(lineTokens[2],lineTokens[3].Trim(trimchars));
							else
								currentTaggedValue.Value = lineTokens[3].Trim(trimchars);
							currentTaggedValue.Update();
							currentElement.TaggedValues.Refresh();
							break;
						case "TABLE-TRIGGER":
							String triggerName		= lineTokens[3].Trim(trimchars);
							String overrideOption	= lineTokens[4];
							String procedure        = lineTokens[5];
							String procedurePath    = lineTokens[6].Trim(trimchars);
							String crcOption		= lineTokens[7];
							String crcValue			= lineTokens[8].Trim(trimchars);
							addTableTrigger(currentElement, triggerName, overrideOption, procedure, procedurePath, crcOption, crcValue);
							break;
						default:
							break;
					}
					
					this.progressNumChars(line.Length);

				}

				currentElement.Update();
				currentElement.Refresh();
				currentPackage.Elements.Refresh();
				this.LogWriteLine("Table - " + currentElement.Name + " created.");

			}

		}

		private void addTableTrigger(EA.Element currentElement, String triggerName, String overrideOption, String procedure, String procedurePath, String crcOption, String crcValue)
		{

			EA.Method		currentMethod      = null;
			EA.MethodTag    currentMethodTag   = null;

			try 
			{

				int pos = currentElement.Methods.Count;				
				if (currentMethod == null)
					currentMethod = (EA.Method) currentElement.Methods.AddNew(triggerName.ToUpper(), "");
				
				currentMethod.Stereotype = "trigger";	
				// currentMethod.Pos = pos;

				try 
				{
					currentMethod.Update();
				}
				catch (Exception e)
				{
					this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
				}
			}
			catch (Exception e)
			{
				this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
			}

			if (overrideOption == "OVERRIDE" || overrideOption == "NO-OVERRIDE")
			{
				currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.GetByName("OVERRIDE");
				if (currentMethodTag == null)
					currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.AddNew("OVERRIDE","");

				if (overrideOption == "OVERRIDE")
					currentMethodTag.Value = "yes";
				else 
				if (overrideOption == "NO-OVERRIDE")
					currentMethodTag.Value = "no";

				currentMethodTag.Update();		
			}
			
			if (procedure == "PROCEDURE") 
			{
				currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.GetByName("PROCEDURE");
				if (currentMethodTag == null)
					currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.AddNew("PROCEDURE", "");
				currentMethodTag.Value = procedurePath;
				currentMethodTag.Update();		
			}

			if (crcOption == "CRC")
			{
				currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.GetByName("CRC");
				if (currentMethodTag == null)
					currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.AddNew("CRC", "");
				currentMethodTag.Value = crcValue;
				currentMethodTag.Update();		
			}
			
			currentMethod.TaggedValues.Refresh();
			currentMethod.Update();
			currentElement.Methods.Refresh();
			currentElement.Update();
			this.LogWriteLine("Table Trigger - " + triggerName.ToLower() + " on table - " + currentElement.Name);

		}

		private void addField(EA.Package currentPackage, String fieldName, String tableName, String dataType)
		{
			EA.Element		currentElement			= null;
			EA.Attribute	currentAttribute		= null;
			EA.AttributeTag	currentAttributeTag		= null;

			try
			{
				currentElement = (EA.Element) currentPackage.Elements.GetByName(tableName);
			}
			catch(Exception e)
			{
                this.LogWriteLine(e.Message + ". Missing table - " + tableName + ".");    
			}


			if (currentElement != null) 
			{
				/* currentAttribute = (EA.Attribute) currentElement.Attributes.GetByName(fieldName); */
				int pos = currentElement.Attributes.Count;
				if (currentAttribute == null)
					currentAttribute = (EA.Attribute) currentElement.Attributes.AddNew(fieldName, dataType.ToUpper());

				currentAttribute.Stereotype = "field";
				currentAttribute.AllowDuplicates = false;
				currentAttribute.IsStatic = false;
				// currentAttribute.Pos = pos;

				try 
				{
					currentAttribute.Update();
				}
				catch (Exception e)
				{
					this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
				}				
				
				char[] separator	= {' '};
				char[] trimchars	= {'\"'};
				String line			= null;
				short idx           = 0;

				while ((line = this.streamReader.ReadLine()) != null)
				{
					
					if (line.Length == 0) 
						break;						

					String[] lineTokens = line.Split(separator);
					String   tagName    = "";
					String   tagValue	= "";
					int thisLength = line.Length;

					if (lineTokens.Length >=3) 
						tagName = lineTokens[2];

					if (lineTokens.Length >= 3 && tagName == "VIEW-AS")
					{
					}
					else
					if (lineTokens.Length >= 3 && tagName == "FIELD-TRIGGER")
					{
						idx = 3;
						for (; idx < lineTokens.Length; idx++)
						{
							tagValue += lineTokens[idx];
							if (idx < (lineTokens.Length - 1))
								tagValue += " ";
						}
					}
					else
					if (lineTokens.Length >= 4 && lineTokens[3].StartsWith("\""))
					{
						idx = 3;
						do 
						{
							for (; idx < lineTokens.Length; idx++)
							{
								tagValue += lineTokens[idx];
								if (idx < (lineTokens.Length - 1))
									tagValue += " ";
							}

							if (tagValue.EndsWith("\""))
								break;

							if ((line = this.streamReader.ReadLine()) != null)
							{
								lineTokens = line.Split(separator);
								idx = 0;
								this.progressNumChars(line.Length);
							}
							else
								break;

						} while (true);
						tagValue = tagValue.Trim(trimchars);
					}
					else
					if (lineTokens.Length >= 4)
						tagValue = lineTokens[3].Trim(trimchars);

					if (tagValue.Length > 255)
						tagValue = tagValue.Substring(0,255);

					if (lineTokens.Length >= 3)
					{
						currentAttributeTag = (EA.AttributeTag) currentAttribute.TaggedValues.AddNew(tagName, tagValue);

					
						switch(tagName)
						{
							case "MANDATORY":
								currentAttribute.AllowDuplicates = true;
                                currentAttributeTag.Value = "yes";
								break;
                            case "CASE-SENSITIVE":
                                currentAttributeTag.Value = "yes";
                                break;
							case "DESCRIPTION":
								currentAttribute.Notes = tagValue;
								break;
							default:
								break;

						}

                        try
                        {
                            currentAttribute.Update();
                        }
                        catch (Exception e)
                        {
                            this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
                        }				

					}
					

					if (currentAttributeTag != null)
					{
						try 
						{
							currentAttributeTag.Update();
						}
						catch (Exception e)
						{
							this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
						}
						currentElement.TaggedValues.Refresh();
					}

					this.progressNumChars(line.Length);
				}

				try 
				{
					currentAttribute.Update();
				}
				catch (Exception e)
				{
					this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
				}

				currentElement.Attributes.Refresh();	
				currentElement.Update();
				
				
				this.LogWriteLine("Field - " + fieldName + " on table - " + tableName);
			}
			
		}

		private void addIndex(EA.Package currentPackage, String indexName, String tableName)
		{
			EA.Element		currentElement		= null;
			EA.Method		currentMethod		= null;
			EA.MethodTag	currentMethodTag	= null;
			EA.Parameter	currentParameter	= null;
			EA.Attribute	currentAttribute	= null;

			try
			{
				currentElement = (EA.Element) currentPackage.Elements.GetByName(tableName);
			}
			catch(Exception e)
			{
                this.LogWriteLine(e.Message + ". Missing table - " + tableName + ".");    
			}

			if (currentElement != null) 
			{
				int pos = currentElement.Methods.Count;
				if (currentMethod == null)
					currentMethod = (EA.Method) currentElement.Methods.AddNew(indexName, "");
				
				currentMethod.Stereotype = "index";
				// currentMethod.Pos = pos;

				try 
				{
					currentMethod.Update();
				}
				catch (Exception e)
				{
					this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
				}

				bool   indexIsPrimary   = false;
				String anotherLine = null;
				while ((anotherLine = this.streamReader.ReadLine()) != null)
				{
					char[] trimchars = {'\"'};

					if (anotherLine.Length == 0) 
						break;						
					else if (anotherLine.StartsWith("  AREA"))
						currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.AddNew(anotherLine.Substring(2,4), anotherLine.Substring(8).TrimEnd(trimchars));
					else if (anotherLine.StartsWith("  UNIQUE"))
					{
						currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.AddNew(anotherLine.Substring(2,6), "yes");
						currentMethod.Stereotype = "unique";
					}
					else if (anotherLine.StartsWith("  PRIMARY"))
					{
						currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.AddNew(anotherLine.Substring(2,7), "yes");
						currentMethod.Stereotype = "PK";
						indexIsPrimary = true;
					}
					else if (anotherLine.StartsWith("  WORD"))
					{
						currentMethodTag = (EA.MethodTag) currentMethod.TaggedValues.AddNew(anotherLine.Substring(2,4), "yes");
						currentMethod.Stereotype = "word-index";

					}
					else if (anotherLine.StartsWith("  INDEX-FIELD"))
					{
						int fIndex = anotherLine.IndexOf('\"', 1);
						int sIndex = anotherLine.IndexOf('\"', fIndex  + 1);

						String indexFieldName = anotherLine.Substring((fIndex + 1),(sIndex - (fIndex + 1)));

						foreach (EA.Attribute thisAttribute in currentElement.Attributes)
						{
							if (thisAttribute.Name == indexFieldName)
							{
								currentAttribute = thisAttribute;
								break;
							}
						}
						if (currentAttribute != null)
						{

							int position = currentMethod.Parameters.Count;
							currentParameter = (EA.Parameter) currentMethod.Parameters.AddNew(currentAttribute.Name, currentAttribute.Type);						
							currentParameter.Position = position;

							if (anotherLine.IndexOf("DESCENDING") > 0) 
								currentParameter.Notes = "DESCENDING";
							else if (anotherLine.IndexOf("ASCENDING") > 0)
								currentParameter.Notes = "ASCENDING";
							else
								currentParameter.Notes = "ASCENDING";
							currentParameter.Update();

							if (indexIsPrimary)
							{
								currentAttribute.IsOrdered = true;
								try 
								{
									currentAttribute.Update();
								}
								catch (Exception e)
								{
									this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
								}
							}
							currentMethod.Parameters.Refresh();
						}
					}

					if (currentMethodTag != null)
					{
						currentMethodTag.Update();
						currentElement.TaggedValues.Refresh();
					}

					this.progressNumChars(anotherLine.Length);
				}

				try 
				{
					currentMethod.Update();
				}
				catch (Exception e)
				{
					this.LogWriteLine("Exception by " + e.TargetSite.ToString() + " - " + e.Message);
				}

				currentMethod.TaggedValues.Refresh();
				currentMethod.Update();
				currentElement.Methods.Refresh();
				currentElement.Update();

				this.LogWriteLine("Index - " + indexName + " on table - " + tableName);
			}
			
		}

		private void addSequence(EA.Package currentPackage, String sequenceName)
		{
			EA.Element     currentElement     = null;
				
			try
			{
				currentElement = (EA.Element) currentPackage.Elements.GetByName(sequenceName);
			}
			catch(Exception e)
			{
                this.LogWriteLine(e.Message + ". Creating sequence - " + sequenceName + ".");    
			}

			if (currentElement == null) 
			{
				int treePos = currentPackage.Elements.Count;
				currentElement = (EA.Element) currentPackage.Elements.AddNew(sequenceName, "Object");
				
				currentElement.Stereotype = "Sequence";
				currentElement.Gentype    = "OpenEdge DB";
				// currentElement.TreePos = treePos;
				currentElement.Update();
				
				char[] separator	= {' '};
				char[] trimchars	= {'\"'};
				String line			= null;

				while ((line = this.streamReader.ReadLine()) != null)
				{
					if (line.Length == 0)
						break;

					String[] lineTokens = line.Split(separator);

					EA.Attribute currentAttribute = null;

					int pos = currentElement.Attributes.Count;
					switch(lineTokens[2])
					{
						case "INITIAL":
							currentAttribute = (EA.Attribute) currentElement.Attributes.AddNew(lineTokens[2], "INTEGER");
							currentAttribute.Default = lineTokens[3];
							break;
						case "INCREMENT":
							currentAttribute = (EA.Attribute) currentElement.Attributes.AddNew(lineTokens[2], "INTEGER");
							currentAttribute.Default = lineTokens[3];
							break;
						case "CYCLE-ON-LIMIT":
							currentAttribute = (EA.Attribute) currentElement.Attributes.AddNew(lineTokens[2], "LOGICAL");
							currentAttribute.Default = lineTokens[3];
							break;
						case "MIN-VAL":
							currentAttribute = (EA.Attribute) currentElement.Attributes.AddNew(lineTokens[2], "INTEGER");
							currentAttribute.Default = lineTokens[3];
							break;
						default:
							break;
					}
					if (currentAttribute != null)
					{
						currentAttribute.Pos = pos;
						currentAttribute.Update();
						currentElement.Attributes.Refresh();
					}

					this.progressNumChars(line.Length);

				}

				currentElement.Update();
				currentElement.Refresh();
				currentPackage.Elements.Refresh();
				this.LogWriteLine("Sequence - " + currentElement.Name + " created.");

			}

		}

		public void createSchemaRelationships2()
		{
			string objectType = eaRepository.GetTreeSelectedItemType().ToString();

			if (objectType != "otPackage")
				System.Windows.Forms.MessageBox.Show("Package not selected");
			else
			{
				this.LogWriteLine("Creating schema relationships...");

				Object		currentObject      = null;
				EA.Package	currentPackage     = null;				

				eaRepository.GetTreeSelectedItem(out currentObject);
				currentPackage = (EA.Package) currentObject;

				foreach (EA.Element primaryElement in currentPackage.Elements) 
				{
				
					
					if (primaryElement.Type == "Class" && primaryElement.Stereotype == "table")
					{
						EA.Method primaryIndexMethod = null;
						foreach (EA.Method currentMethod in primaryElement.Methods)
						{
							if (currentMethod.Stereotype == "PK")
								primaryIndexMethod = currentMethod;
						}

						if (primaryIndexMethod != null)
						{

							foreach (EA.Element foreignElement in currentPackage.Elements)
							{
								if (foreignElement.ElementID != primaryElement.ElementID)
								{
									bool foreignElementMatch = true;
									foreach (EA.Parameter primaryIndexParameter in primaryIndexMethod.Parameters)
									{
										bool foreignAttributeMatch = false;
										foreach (EA.Attribute foreignAttribute in foreignElement.Attributes)
										{
											if (foreignAttribute.Name == primaryIndexParameter.Name &&
												foreignAttribute.Type == primaryIndexParameter.Type)
											{
												foreignAttributeMatch = true;
												break;
											}
										}
										if (foreignAttributeMatch == false)
										{
											foreignElementMatch = false;
											break;
										}
									}

									if (foreignElementMatch)
									{
										EA.Connector currentConnector = 
											(EA.Connector) foreignElement.Connectors.AddNew("FK_" + foreignElement.Name + "_" + primaryElement.Name,"Association");
										currentConnector.SupplierID = primaryElement.ElementID;
										currentConnector.Stereotype = "FK";
										currentConnector.Direction = "Source -> Destination";
										currentConnector.Update();
										
										
										EA.ConnectorEnd clientEnd	= currentConnector.ClientEnd;
										EA.ConnectorEnd supplierEnd = currentConnector.SupplierEnd;

										supplierEnd.Role = primaryIndexMethod.Name;
										supplierEnd.Cardinality = "1";
										supplierEnd.Update();

										EA.Method foreignMethod = null;
										foreach (EA.Method currentMethod in foreignElement.Methods)
										{
											if (currentMethod.Name == "FK_" + foreignElement.Name + "_" + primaryElement.Name)
											{
												foreignMethod = currentMethod;
												break;
											}
										}

										if (foreignMethod == null)
										{
											foreignMethod = (EA.Method) foreignElement.Methods.AddNew("FK_" + foreignElement.Name + "_" + primaryElement.Name, "");
											foreignMethod.Stereotype = "FK";
											foreignMethod.Update();
											foreignElement.Methods.Refresh();

											foreach (EA.Parameter primaryIndexParameter in primaryIndexMethod.Parameters)
											{
												EA.Parameter foreignMethodParameter = (EA.Parameter) foreignMethod.Parameters.AddNew(primaryIndexParameter.Name, primaryIndexParameter.Type);
												foreignMethodParameter.Kind = primaryIndexParameter.Kind;
												foreignMethodParameter.Update();
											}
											foreignMethod.Parameters.Refresh();
										}

										String foreignCardinality = "1..*";

										clientEnd.Role = foreignMethod.Name;
										clientEnd.Cardinality = foreignCardinality;
										clientEnd.Update();

										currentConnector.Update();
										foreignElement.Connectors.Refresh();
										
									}
								}
							
							}

							this.LogWriteLine("Relationships created for " + primaryElement.Name);			
						}
					}

				}

			}

		}

		public void createSchemaRelationships(EA.Package currentPackage)
		{

			this.LogWriteLine("Creating schema relationships...");

			foreach (EA.Element primaryElement in currentPackage.Elements) 
			{
			
				
				if (primaryElement.Type == "Class" && primaryElement.Stereotype == "table")
				{
					EA.Method primaryIndexMethod = null;
					foreach (EA.Method currentMethod in primaryElement.Methods)
					{
						if (currentMethod.Stereotype == "PK")
							primaryIndexMethod = currentMethod;
					}

					if (primaryIndexMethod != null)
					{

						foreach (EA.Element foreignElement in currentPackage.Elements)
						{
							if (foreignElement.ElementID != primaryElement.ElementID)
							{
								bool foreignElementMatch = true;
								foreach (EA.Parameter primaryIndexParameter in primaryIndexMethod.Parameters)
								{
									bool foreignAttributeMatch = false;
									foreach (EA.Attribute foreignAttribute in foreignElement.Attributes)
									{
										if (foreignAttribute.Name == primaryIndexParameter.Name &&
											foreignAttribute.Type == primaryIndexParameter.Type)
										{
											foreignAttributeMatch = true;
											break;
										}
									}
									if (foreignAttributeMatch == false)
									{
										foreignElementMatch = false;
										break;
									}
								}

								if (foreignElementMatch)
								{
									EA.Connector currentConnector = 
										(EA.Connector) foreignElement.Connectors.AddNew("FK_" + foreignElement.Name + "_" + primaryElement.Name,"Association");
									currentConnector.SupplierID = primaryElement.ElementID;
									currentConnector.Stereotype = "FK";
									currentConnector.Direction = "Source -> Destination";
									currentConnector.Update();
									
									
									EA.ConnectorEnd clientEnd	= currentConnector.ClientEnd;
									EA.ConnectorEnd supplierEnd = currentConnector.SupplierEnd;

									supplierEnd.Role = primaryIndexMethod.Name;
									supplierEnd.Cardinality = "1";
									supplierEnd.Update();

									EA.Method foreignMethod = null;
									foreach (EA.Method currentMethod in foreignElement.Methods)
									{
										if (currentMethod.Name == "FK_" + foreignElement.Name + "_" + primaryElement.Name)
										{
											foreignMethod = currentMethod;
											break;
										}
									}

									if (foreignMethod == null)
									{
										foreignMethod = (EA.Method) foreignElement.Methods.AddNew("FK_" + foreignElement.Name + "_" + primaryElement.Name, "");
										foreignMethod.Stereotype = "FK";
										foreignMethod.Update();
										foreignElement.Methods.Refresh();

										foreach (EA.Parameter primaryIndexParameter in primaryIndexMethod.Parameters)
										{
											EA.Parameter foreignMethodParameter = (EA.Parameter) foreignMethod.Parameters.AddNew(primaryIndexParameter.Name, primaryIndexParameter.Type);
											foreignMethodParameter.Kind = primaryIndexParameter.Kind;
											foreignMethodParameter.Update();
										}
										foreignMethod.Parameters.Refresh();
									}

									String foreignCardinality = "1..*";

									clientEnd.Role = foreignMethod.Name;
									clientEnd.Cardinality = foreignCardinality;
									clientEnd.Update();

									currentConnector.Update();
									foreignElement.Connectors.Refresh();
									
								}
							}
						
						}

						this.LogWriteLine("Relationships created for " + primaryElement.Name);			
					}
				}

			}


		}

		public void createSchemaDiagram(EA.Package currentPackage)
		{

			EA.Diagram currentDiagram = (EA.Diagram) currentPackage.Diagrams.AddNew(currentPackage.Name, "Class");
			currentDiagram.Update();
			currentPackage.Diagrams.Refresh();

			foreach (EA.Element thisElement in currentPackage.Elements) 
			{
				EA.DiagramObject currentDiagramObject = (EA.DiagramObject) currentDiagram.DiagramObjects.AddNew("","");
				currentDiagramObject.ElementID = thisElement.ElementID;
				currentDiagramObject.Update();
				currentDiagram.DiagramObjects.Refresh();
			}

			eaRepository.GetProjectInterface().LayoutDiagram(currentDiagram.DiagramGUID,0);	
			eaRepository.SaveDiagram(currentDiagram.DiagramID);
			eaRepository.CloseDiagram(currentDiagram.DiagramID);

		}

		public void createSchemaDiagram2()
		{
			string objectType = eaRepository.GetTreeSelectedItemType().ToString();

			if (objectType != "otPackage")
				System.Windows.Forms.MessageBox.Show("Package not selected");
			else
			{
				Object		currentObject      = null;
				EA.Package	currentPackage     = null;				

				eaRepository.GetTreeSelectedItem(out currentObject);
				currentPackage = (EA.Package) currentObject;

				//EA.Diagram currentDiagram = (EA.Diagram) currentPackage.Diagrams.AddNew(currentPackage.Name, "Class");
				//currentDiagram.Update();
				//currentPackage.Diagrams.Refresh();

				foreach (EA.Element thisElement in currentPackage.Elements) 
				{
                    EA.Diagram currentDiagram = (EA.Diagram) thisElement.Diagrams.AddNew(thisElement.Name, "Class");
                    currentDiagram.Update();
                    thisElement.Diagrams.Refresh();

					//EA.DiagramObject currentDiagramObject = (EA.DiagramObject) currentDiagram.DiagramObjects.AddNew("","");
					//currentDiagramObject.ElementID = thisElement.ElementID;
					//currentDiagramObject.Update();
					//currentDiagram.DiagramObjects.Refresh();
				}
                

				//eaRepository.GetProjectInterface().LayoutDiagram(currentDiagram.DiagramGUID,0);


			}

		}


		#region IDisposable Members

		public void Dispose()
		{
			this.eaRepository = null;
		}

		#endregion
	}
}
